import asyncio
import concurrent.futures
from ossaudiodev import control_names
import random
from typing import List, Dict, Tuple, Optional, Set
import numpy as np
import cv2
import os
from loguru import logger
from managers.ctl_manager import CenterlineManager, CtlPoint
from scipy.ndimage import convolve
from skimage.morphology import dilation, disk, skeletonize
from skimage.measure import label, regionprops
from skimage.draw import line

class VesselManager:
    
    def __init__(self):
        self.less_point_tag = True  # 是否减少中心线点数的标志
        self.min_branch_length = 10  # 最小分支长度阈值，用于去除小毛刺
        self.min_component_area = 20  # 最小连通域面积阈值
    
    # ---------------- 外部函数 ----------------
    async def set_vessel_message(self, dict):
        for key, value in dict.items():
            setattr(self, key, value)
    
    def set_less_point_tag(self, enable: bool):
        """设置是否减少中心线点数"""
        self.less_point_tag = enable
    
    def set_min_branch_length(self, length: int):
        """设置最小分支长度阈值，小于此长度的分支将被移除"""
        if length > 0:
            self.min_branch_length = length
            logger.info(f"已设置最小分支长度阈值为: {length}")
        else:
            logger.warning("最小分支长度必须大于0")
    
    def set_min_component_area(self, area: int):
        """设置最小连通域面积阈值，小于此面积的连通域将被移除"""
        if area > 0:
            self.min_component_area = area
            logger.info(f"已设置最小连通域面积阈值为: {area}")
        else:
            logger.warning("最小连通域面积必须大于0")
    
    async def get_skeleton(self):
        logger.info(f"开始获取血管骨架图")
        if getattr(self, 'seg_data', None) is None:
            raise ValueError("seg_data未设置")
        
        segmentation = self.seg_data.astype(np.uint8)
        skeleton = skeletonize(segmentation)
        
        # 第一步：处理骨架（去除小连通域）
        skeleton = self._process_skeleton(skeleton)
        logger.debug("已完成小连通域过滤")
        
        # 第二步：去除小毛刺
        skeleton = self._remove_short_branches(skeleton, min_branch_length=self.min_branch_length)
        logger.debug("已完成小毛刺去除")
        
        # 第三步：融合分叉点
        skeleton = self._fuse_junction_blobs_on_skeleton(skeleton)
        logger.debug("已完成分叉点融合")
        
        setattr(self, 'skeleton', skeleton)
        logger.info(f"血管骨架图获取成功")
        return skeleton

    async def get_vessel_centerline(self):
        logger.info(f"开始获取血管中心线")
        skeleton = (self.skeleton!=0).astype(np.uint8)
        retval, labels, stats, centroids = cv2.connectedComponentsWithStats(skeleton, connectivity=8)
        point_index = self._set_point_index(skeleton)
        self.ctl_list = []
        if retval-1 > 1:
            logger.warning(f"血管骨架图连通域数大于1，可能存在多个血管，请检查")
        
        # 创建并发处理每个连通域的任务
        async def process_connected_component(i):
            draw_seg =(labels == i).astype(np.uint8)
            if np.sum(draw_seg) < 100:
                return None
            
            if i !=1:
                print('debug')
            ctl = CenterlineManager()
            extreme, bifurcations = ctl.find_extreme_point(draw_seg)
            # 后续可以引入端点位置的血管半径来判断，起始点半径大于端点半径
            if (self.dsa_position == 'LS' or self.dsa_position == 'F') and i == 1:
                start_point_coords = ctl.find_start_point(extreme, draw_seg, self.main_vessel_result)
            else:
                start_point_coords = ctl.find_start_point(extreme, draw_seg)
            target_points = extreme + bifurcations
            # 删除start_point - 根据坐标找到对应的CtlPoint对象并删除
            for point in target_points[:]:  # 创建副本来避免在迭代时修改列表
                if point.point == start_point_coords:
                    target_points.remove(point)
                    break
                
            # 构建所有路径
            ctl_path = ctl.example_usage_path_decomposition(skeleton, ctl.start_point, target_points)
            
            return ctl, ctl_path
        
        # 并发处理所有连通域
        tasks = [asyncio.create_task(process_connected_component(i)) for i in range(1, retval)]
        results = await asyncio.gather(*tasks)
        # 收集有效的结果
        self.ctl_list = []
        all_ctl_path = []
        for ctl in results:
            if ctl is not None:
                self.ctl_list.append(ctl[0])
                all_ctl_path.extend(ctl[1])
        self.all_ctl_path = all_ctl_path
        self.color_vessel_paths(self.named_result[0][0], self.main_vessel_result)
        return self.ctl_list
    
     
    def color_vessel_paths(self, named_result: np.ndarray, main_vessel_result):
        """
        根据命名血管染色
        """
        all_paths = self.all_ctl_path
        # 根据血管的坐标点个数排序

        ctl_named_result = np.zeros_like(named_result)
                # 单独给左冠主动脉5号段染色
        if main_vessel_result is not None:
            for path in all_paths:
                point_color = []
                for point in path:
                    point_color.append(named_result[point[1], point[0]])
                if 7 in point_color and 8 in point_color and 6 not in point_color:
                    for point in path[:len(path)//2]:
                        if ctl_named_result[point[1], point[0]] == 0:
                            ctl_named_result[point[1], point[0]] = 7
                    for point in path[len(path)//2:]:
                        if ctl_named_result[point[1], point[0]] == 0:
                            ctl_named_result[point[1], point[0]] = 8
                else:
                    for point in path:
                        if ctl_named_result[point[1], point[0]] == 0:
                            color_list = np.argsort(np.bincount(point_color))[::-1]
                            color_index = color_list[0]
                            ctl_named_result[point[1], point[0]] = color_index
        else:
            for path in all_paths:
                point_color = []
                for point in path:
                    if ctl_named_result[point[1], point[0]] == 0:
                        ctl_named_result[point[1], point[0]] = named_result[point[1], point[0]]

        self.ctl_named_result = ctl_named_result 
        return ctl_named_result
    
    def get_path_coordinates(self):
        """
        获取所有路径的坐标序列
        
        Returns:
            坐标序列列表的列表，外层列表对应连通域，内层列表对应路径
        """
        if not hasattr(self, 'ctl_list') or not self.ctl_list:
            logger.warning("中心线管理器列表为空，请先调用get_vessel_centerline()方法")
            return []
        
        all_coordinates = []
        
        for ctl in self.ctl_list:
            coordinates = ctl.get_centerline_coordinates()
            all_coordinates.append(coordinates)
        
        return all_coordinates
    
    async def return_result(self):
        item = {
            'segment_segmentation': {},
            'lesion_detection': [],
            'occlusion_detection': []
        }
        for i, result in enumerate(self.lesion_result[0]['bbox']):
            box = result[:4]
            if box[0] == box[1]== box[2] == box[3] == 0:
                continue
            box = [int(i) for i in box]
            # 左上右下坐标转为四个角点的坐标
            box = [[box[0], box[1]], [box[0], box[3]], [box[2], box[1]], [box[2], box[3]]]
            tmp_result = {
                'box': box,
                'score': result[4],
                'type': 'lesion'
            }
            item['lesion_detection'].append(tmp_result)
        for i, result in enumerate(self.lesion_result[0]['bbox']):
            box = result[:4]
            if box[0] == box[1]== box[2] == box[3] == 0:
                continue
            box = [int(i) for i in box]
            # 左上右下坐标转为四个角点的坐标
            box = [[box[0], box[1]], [box[0], box[3]], [box[2], box[1]], [box[2], box[3]]]
            tmp_result = {
                'box': box,
                'score': result[4],
                'type': 'occlusion'
            }
            item['occlusion_detection'].append(tmp_result)
        
        item['segment_segmentation']['mask'] = self.seg_data.astype(np.uint8).tolist() if self.seg_data is not None else np.zeros((512, 512)).astype(np.uint8).tolist()
        item['segment_segmentation']['centerline'] = self.ctl_named_result.astype(np.uint8).tolist() if self.ctl_named_result is not None else np.zeros((512, 512)).astype(np.uint8).tolist()
        
        return item
    
    async def visulize_vessel_msg(self, centerline_result, save_path):
        logger.info(f"开始可视化血管信息")
        
        # 创建并发写入图像的任务
        async def write_image(filename, data, description):
            try:
                if data is None:
                    logger.warning(f"{description}未设置")
                    return 0
                # 在线程池中执行IO密集型的图像写入操作
                
                loop = asyncio.get_event_loop()
                with concurrent.futures.ThreadPoolExecutor() as executor:
                    await loop.run_in_executor(
                        executor, 
                        cv2.imwrite, 
                        os.path.join(save_path, filename), 
                        data.astype(np.uint8)
                    )
                logger.debug(f"成功写入 {filename}")
            except Exception as e:
                logger.error(f"写入 {filename} 失败: {e}")
                return 0

        # 准备要写入的图像数据
        img_data = getattr(self, 'img_data', None)
        seg_data = getattr(self, 'seg_data', None)
        skeleton_data = getattr(self, 'skeleton', None)
        named_data = getattr(self, 'named_result', None)
        main_vessel_data = getattr(self, 'main_vessel_result', None)
        all_ctl_path = getattr(self, 'all_ctl_path', None)
        ctl_named_result = getattr(self, 'ctl_named_result', None)
        lesion_result = getattr(self, 'lesion_result', None)
        occlusion_result = getattr(self, 'occlusion_result', None)
        # 预处理数据
        seg_data_processed = cv2.addWeighted(img_data, 0.6, (seg_data * 255).astype(np.uint8), 0.4, 0) if seg_data is not None else None
        skeleton_data_processed = cv2.addWeighted(img_data, 0.6, (skeleton_data*255).astype(np.uint8), 0.4, 0) if skeleton_data is not None else None
        
        named_data_processed = cv2.addWeighted(cv2.cvtColor(img_data, cv2.COLOR_GRAY2RGB), 0.6, self._numberToRGBColor(named_data[0][0]), 0.4, 0) if named_data is not None else None
        
        main_vessel_lad_processed = cv2.addWeighted(img_data, 0.6, main_vessel_data[0] *255, 0.4, 0) if main_vessel_data is not None else None
        main_vessel_lcx_processed = cv2.addWeighted(img_data, 0.6, main_vessel_data[1] *255, 0.4, 0) if main_vessel_data is not None else None
        
        # 绘制检测框
        detection_boxes_processed = None
        if img_data is not None:
            # 将灰度图转为RGB以便绘制彩色检测框
            detection_boxes_processed = cv2.cvtColor(img_data, cv2.COLOR_GRAY2RGB).copy()
            
            # 绘制病变和闭塞检测框
            # 根据return_result方法的逻辑，所有检测框都存储在lesion_result中
            if lesion_result is not None and len(lesion_result) > 0 and 'bbox' in lesion_result[0]:
                bbox_list = lesion_result[0]['bbox']
                lesion_count = 0
                occlusion_count = 0
                
                for i, bbox_info in enumerate(bbox_list):
                    box = bbox_info[:4]
                    score = bbox_info[4] if len(bbox_info) > 4 else 0
                    # 跳过空框
                    if box[0] == box[1] == box[2] == box[3] == 0:
                        continue
                    
                    # 左上角和右下角坐标
                    x1, y1, x2, y2 = int(box[0]), int(box[1]), int(box[2]), int(box[3])
                    
                    # 根据索引位置或其他规则区分病变和闭塞
                    # 这里假设所有框都是病变框，如果有具体的区分规则可以调整
                    # 绘制红色矩形框表示病变/检测结果
                    cv2.rectangle(detection_boxes_processed, (x1, y1), (x2, y2), (0, 0, 255), 2)
                    # 添加置信度标签
                    label = f'Detection: {score:.2f}'
                    cv2.putText(detection_boxes_processed, label, (x1, y1-10), 
                              cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
                    lesion_count += 1
                
                logger.debug(f"已绘制 {lesion_count} 个检测框")
            
            # 如果存在单独的闭塞检测结果，也绘制出来（蓝色）
            if occlusion_result is not None and len(occlusion_result) > 0 and 'bbox' in occlusion_result[0]:
                occlusion_count = 0
                for bbox_info in occlusion_result[0]['bbox']:
                    box = bbox_info[:4]
                    score = bbox_info[4] if len(bbox_info) > 4 else 0
                    # 跳过空框
                    if box[0] == box[1] == box[2] == box[3] == 0:
                        continue
                    # 左上角和右下角坐标
                    x1, y1, x2, y2 = int(box[0]), int(box[1]), int(box[2]), int(box[3])
                    # 绘制蓝色矩形框表示闭塞
                    cv2.rectangle(detection_boxes_processed, (x1, y1), (x2, y2), (255, 0, 0), 2)
                    # 添加置信度标签
                    label = f'Occlusion: {score:.2f}'
                    cv2.putText(detection_boxes_processed, label, (x1, y1-10), 
                              cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
                    occlusion_count += 1
                logger.debug(f"已绘制 {occlusion_count} 个闭塞检测框")
        
        # 并发写入所有图像 
        tasks = [
            write_image('img.png', img_data, 'img_data'),
            write_image('seg.png', seg_data_processed, 'seg_data'),
            write_image('skeleton.png', skeleton_data_processed, 'skeleton'),
            write_image('named.png', named_data_processed, 'named'),
        ]
        if main_vessel_data is not None:
            tasks.append(write_image('main_vessel_lad.png', main_vessel_lad_processed, 'main_vessel_lad'))
            tasks.append(write_image('main_vessel_lcx.png', main_vessel_lcx_processed, 'main_vessel_lcx'))
        
        # 添加检测框可视化图像
        if detection_boxes_processed is not None:
            tasks.append(write_image('detection_boxes.png', detection_boxes_processed, 'detection_boxes'))
        
        await asyncio.gather(*tasks)
        
        # 如果存在中心线管理器，也进行路径可视化
        if all_ctl_path:
            logger.info("开始生成血管路径可视化")
            try:
                # 将原始图像和分割图像转换为RGB格式
                tmp_img = img_data.copy()
                tmp_img = cv2.cvtColor(tmp_img, cv2.COLOR_GRAY2RGB)
                tmp_seg = skeleton_data.copy().astype(np.uint8) * 255
                tmp_seg = cv2.cvtColor(tmp_seg, cv2.COLOR_GRAY2RGB)
                
                # 融合两张图像 (权重可调整，这里使用0.6和0.4)
                fused_img = cv2.addWeighted(tmp_img, 0.6, tmp_seg, 0.4, 0)
                temp_draw = fused_img.copy()
                for i, points in enumerate(all_ctl_path):
                    random.seed(i)
                    color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
                    for p in points:
                        # 随机颜色
                        cv2.circle(temp_draw, p, 1, color, -1)
                await write_image(f'ctl_path.png', temp_draw, f'ctl_path')
                ctl_named = cv2.addWeighted(cv2.cvtColor(img_data, cv2.COLOR_GRAY2RGB), 0.6, self._numberToRGBColor(ctl_named_result), 0.4, 0) if ctl_named_result is not None else None
                await write_image(f'ctl_named.png', ctl_named, f'ctl_named')
            except Exception as e:
                logger.warning(f"路径可视化失败: {e}")
        
        logger.info(f"血管信息可视化成功，保存路径：{save_path}")
        return 1
    
    # ---------------- 内部调用函数 ----------------
    def _fuse_junction_blobs_on_skeleton(self, skel, r_merge=2, re_skeletonize=True):
        """
        skel: 二值骨架，True/1 为骨架像素
        r_merge: 交叉像素的融合半径（像素），常用 1~3
        """
        skel = skel.astype(bool)
        # 1) 邻居计数，找候选交叉像素（度≥3）
        K = np.array([[1,1,1],[1,0,1],[1,1,1]], dtype=np.uint8)
        deg = convolve(skel.astype(np.uint8), K, mode='constant', cval=0)
        junc_cand = skel & (deg >= 3)

        if not np.any(junc_cand):
            return skel  # 没有需要融合的交叉

        # 2) 膨胀候选，得到“交叉区域”，并与骨架求交以限定在骨架范围内
        blob_mask = dilation(junc_cand, footprint=disk(r_merge)) & skel

        # 3) 对每个交叉区域做融合与重连
        lbl = label(blob_mask, connectivity=2)
        out = skel.copy()
        H, W = skel.shape

        # 获取8邻域坐标生成器
        def n8(r,c):
            for dr in (-1,0,1):
                for dc in (-1,0,1):
                    if dr==0 and dc==0: continue
                    rr, cc = r+dr, c+dc
                    if 0 <= rr < H and 0 <= cc < W:
                        yield rr, cc

        for reg in regionprops(lbl):
            coords = reg.coords  # 该交叉区域内所有骨架像素
            if len(coords) <= 1:
                continue

            # 3.1 找到“支路口”（ports）：在交叉区域边界、且与区域外骨架相邻的像素
            coords_set = set(map(tuple, coords))
            ports = []       # 与区域外的骨架的交界像素（在区域内的一侧）
            outside_pts = [] # 对应的区域外第一骨架像素
            for r, c in coords:
                for rr, cc in n8(r,c):
                    if (rr, cc) not in coords_set and skel[rr, cc]:
                        ports.append((r,c))
                        outside_pts.append((rr,cc))
            # port 太少（<3）通常不是“糊”而是正常的转折，跳过
            if len(set(ports)) < 3:
                continue

            # 3.2 选代表点：用区域几何中心就够稳健；用“中值点/medoid”更抗偏
            rc = np.mean(coords, axis=0)
            rc = tuple(np.round(rc).astype(int))
            # 若中心不在区域内，取最近区域像素
            if rc not in coords_set:
                d2 = [( (r-rc[0])**2 + (c-rc[1])**2, (r,c) ) for r,c in coords]
                rc = min(d2)[1]

            # 3.3 清空该交叉区域里的骨架像素
            out[tuple(zip(*coords))] = False

            # 3.4 从代表点到每个 port 画一条直线，但**只保留交叉区域掩膜内**的像素，避免越界破坏原骨架
            # 为了稳健，把“区域掩膜”稍微扩一点容忍锯齿
            local_mask = dilation(lbl==reg.label, footprint=disk(max(1, r_merge)))
            r0, c0 = rc
            for (rp, cp) in set(ports):
                rr, cc = line(r0, c0, rp, cp)
                keep = [(r, c) for r, c in zip(rr, cc) if 0 <= r < H and 0 <= c < W and local_mask[r, c]]
                if keep:
                    rs, cs = zip(*keep)
                    out[rs, cs] = True

            # 3.5 把每个 port 的“外侧第一骨架像素”也接上避免断开
            for (ro, co) in set(outside_pts):
                # 代表点到外侧点之间可能只差1像素，已连；不强求
                out[ro, co] = True

        # 4) 可选：重薄化，保证1像素宽
        if re_skeletonize:
            out = skeletonize(out)
        return out
    
    
    def _process_skeleton(self,skeleton):
        origin_skeleton = skeleton.astype(np.uint8)                   
        # 计算骨架图的连通域数
        retval, labels, stats, centroids = cv2.connectedComponentsWithStats(origin_skeleton, connectivity=8)
        new_retval = []
        for i in range(1,retval):
            # 如果连通域的面积小于阈值，则将其从骨架图中移除（提高阈值以更好地过滤小连通域）
            area = stats[i, cv2.CC_STAT_AREA]
            if area < self.min_component_area:  # 使用实例变量中的阈值
                labels[labels == i] = 0
            else:
                new_retval.append(i)
        tmp_skeleton = (labels != 0).astype(np.uint8)
        return tmp_skeleton

    def _remove_short_branches(self, skeleton, min_branch_length=10):
        """
        去除骨架图中的短分支（小毛刺）
        
        Args:
            skeleton: 输入的骨架图 (numpy array)
            min_branch_length: 最小分支长度阈值，小于此长度的分支将被移除
            
        Returns:
            处理后的骨架图
        """
        skeleton = skeleton.astype(np.uint8)
        result = skeleton.copy()
        
        # 定义8邻域核用于计算邻居数量
        kernel = np.array([[1,1,1],[1,0,1],[1,1,1]], dtype=np.uint8)
        
        # 迭代处理，直到没有更多短分支可以移除
        max_iterations = 50  # 防止无限循环
        iteration = 0
        
        while iteration < max_iterations:
            # 计算每个像素的邻居数量（度数）
            neighbor_count = convolve(result.astype(np.uint8), kernel, mode='constant', cval=0)
            
            # 找到所有端点（度数为1的骨架像素）
            endpoints = (result == 1) & (neighbor_count == 1)
            endpoint_coords = np.where(endpoints)
            
            if len(endpoint_coords[0]) == 0:
                break  # 没有端点了，退出循环
            
            branches_to_remove = []
            
            # 从每个端点开始追踪分支
            for i in range(len(endpoint_coords[0])):
                start_y, start_x = endpoint_coords[0][i], endpoint_coords[1][i]
                if result[start_y, start_x] == 0:  # 该点可能已被移除
                    continue
                
                # 追踪从端点开始的分支路径
                branch_path = self._trace_branch_from_endpoint(result, start_x, start_y, neighbor_count)
                
                # 如果分支长度小于阈值，标记为需要移除
                if len(branch_path) < min_branch_length:
                    branches_to_remove.extend(branch_path)
            
            if not branches_to_remove:
                break  # 没有短分支需要移除，退出循环
            
            # 移除短分支
            for x, y in branches_to_remove:
                if 0 <= y < result.shape[0] and 0 <= x < result.shape[1]:
                    result[y, x] = 0
            
            iteration += 1
        
        logger.debug(f"去除小毛刺完成，迭代次数: {iteration}")
        return result

    def _trace_branch_from_endpoint(self, skeleton, start_x, start_y, neighbor_count):
        """
        从端点开始追踪分支路径，直到遇到分叉点或另一个端点
        
        Args:
            skeleton: 骨架图
            start_x, start_y: 起始端点坐标
            neighbor_count: 每个像素的邻居数量
            
        Returns:
            分支路径上的坐标列表 [(x1,y1), (x2,y2), ...]
        """
        path = [(start_x, start_y)]
        current_x, current_y = start_x, start_y
        visited = set([(start_x, start_y)])
        
        while True:
            # 8邻域方向
            directions = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
            next_point = None
            
            # 寻找下一个骨架像素
            for dx, dy in directions:
                next_x, next_y = current_x + dx, current_y + dy
                
                # 检查边界
                if (0 <= next_y < skeleton.shape[0] and 0 <= next_x < skeleton.shape[1] and
                    skeleton[next_y, next_x] == 1 and (next_x, next_y) not in visited):
                    next_point = (next_x, next_y)
                    break
            
            if next_point is None:
                break  # 没有下一个点，分支结束
            
            current_x, current_y = next_point
            path.append(next_point)
            visited.add(next_point)
            
            # 如果到达分叉点（度数>=3）或另一个端点，停止追踪
            # 但不包括分叉点本身在要移除的路径中
            if neighbor_count[current_y, current_x] >= 3:
                path.pop()  # 移除分叉点，保留分叉点
                break
            elif neighbor_count[current_y, current_x] == 1 and len(path) > 1:
                break  # 到达另一个端点
        
        return path

    def _set_point_index(self, skeleton):
        point = np.where(skeleton == 1)
        point_index = {}
        index = 0
        for x, y in zip(point[0], point[1]):
            point_index[(y,x)] = index
            index += 1
        return point_index

    def _numberToRGBColor(self, segment):
        colors = np.array([
            [0, 0, 0],        # 黑色
            [255, 0, 0],      # 红色
            [0, 255, 0],      # 绿色
            [0, 0, 255],      # 蓝色
            [255, 255, 0],    # 黄色
            [0, 255, 255],    # 青色
            [255, 0, 255],    # 洋红
            [192, 192, 192],  # 银色
            [128, 128, 128],  # 灰色
            [128, 0, 0],      # 深红
            [128, 128, 0],    # 橄榄色
            [0, 128, 0],      # 深绿色
            [128, 0, 128],    # 紫色
            [0, 128, 128],    # 青绿色
            [0, 0, 128],      # 深蓝色
            [255, 165, 0],    # 橙色
            [255, 192, 203],  # 粉色
            [245, 245, 220],  # 米色
            [47, 79, 79],     # 暗灰色
            [255, 215, 0],    # 金色
            [173, 216, 230],  # 淡蓝色
            [173, 216, 0],    # 黄绿色
            [75, 0, 130],     # 靛蓝色
            [255, 20, 147],   # 深粉色
            [124, 252, 0],    # 草绿色
            [0, 255, 127],    # 绿松石色
            [70, 130, 180],   # 钢蓝色
        ], dtype=np.uint8)

        if segment is None:
            return None

        # 检查 segment 是否是 NumPy 数组
        segment = np.array(segment, dtype=np.int32)
        # 加粗segment
        segment = dilation(segment, disk(2))

        # 创建 RGB 图像（512×512×3）
        rgb_image = colors[segment % len(colors)]  # 防止超出颜色索引范围

        # 在每个segment区域标记编号
        unique_segments = np.unique(segment)
        unique_segments = unique_segments[unique_segments > 0]  # 排除背景（0）
        
        for seg_num in unique_segments:
            # 找到当前segment的所有像素位置
            mask = (segment == seg_num)
            coords = np.argwhere(mask)
            
            if len(coords) > 0:
                # 计算质心位置
                centroid_y = int(np.mean(coords[:, 0]))
                centroid_x = int(np.mean(coords[:, 1]))
                
                # 在质心位置标记编号
                text = str(seg_num)
                font = cv2.FONT_HERSHEY_SIMPLEX
                font_scale = 0.5
                thickness = 2
                
                # 获取文本大小以便添加背景
                (text_width, text_height), baseline = cv2.getTextSize(text, font, font_scale, thickness)
                
                # 绘制白色背景矩形使文字更清晰
                cv2.rectangle(rgb_image, 
                             (centroid_x - 5, centroid_y - text_height - 5),
                             (centroid_x + text_width + 5, centroid_y + 5),
                             (255, 255, 255), -1)
                
                # 绘制黑色文字
                cv2.putText(rgb_image, text, (centroid_x, centroid_y), 
                           font, font_scale, (0, 0, 0), thickness, cv2.LINE_AA)

        return rgb_image

# 使用示例:
# """
# # 创建血管管理器实例
# vessel_manager = VesselManager()
# 
# # 设置血管信息（图像数据和分割数据）
# vessel_manager.set_vessel_message({
#     'img_data': your_image_data,  # 原始图像数据
#     'seg_data': your_segmentation_data  # 血管分割结果
# })
# 
# # 获取骨架图
# skeleton = vessel_manager.get_skeleton()
# 
# # 获取中心线（包含路径构建）
# centerlines = vessel_manager.get_vessel_centerline()
# 
# # 构建血管路径（从起始点到各端点）
# paths = vessel_manager.build_vessel_paths(save_path='./vessel_analysis')
# 
# # 获取路径坐标
# coordinates = vessel_manager.get_path_coordinates()
# 
# # 可视化所有血管信息（包括路径）
# vessel_manager.visulize_vessel_msg('./vessel_visualization')
# 
# 说明：
# 1. 端点：在血管骨架图上能够找到的真实端点
# 2. 分叉点：经过融合处理的分叉点，无法在原始骨架图上找到确切位置
# 3. 路径构建：使用A*算法在骨架图上寻找最优路径，优先经过融合后的分叉点
# 4. 可视化：生成多个图像文件，包括原图、分割图、骨架图、路径图等
# """